package org.oded.logging;

import java.io.IOException;
import java.util.Collection;
import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.log4j.DailyRollingFileAppender;
import org.apache.log4j.FileAppender;
import org.apache.log4j.MDC;
import org.apache.log4j.helpers.LogLog;
import org.apache.log4j.spi.LoggingEvent;

public class CustomerFileAppender extends FileAppender
{
	// use a concurrent hashmap since this is geared for many reads, few writes
	private ConcurrentHashMap<String, FileAppender> customerAppenders;
	
	public static final String MDC_CUSTOMER_KEY = "customer";
	public static final String ALL_CUSTOMER = "all";

	public CustomerFileAppender()
	{
		customerAppenders = new ConcurrentHashMap<String, FileAppender>();
	}

	@Override
	public void append( LoggingEvent event )
	{
		String customerName = (String) MDC.get( MDC_CUSTOMER_KEY );
		if ( customerName == null ) // if the customer name is not set then log the message in a log file for all the customers 
		{
			customerName = ALL_CUSTOMER;
		}

		FileAppender fileAppender = null;

		fileAppender = customerAppenders.get( customerName );
		if ( fileAppender == null )
		{
			fileAppender = createFileAppender( customerName );
			if ( fileAppender != null )
			{
				fileAppender.activateOptions();
				customerAppenders.put( customerName, fileAppender );
			}
		}

		if ( fileAppender != null )
		{
			fileAppender.append( event );
		}
	}

	private FileAppender createFileAppender( String clientName )
	{
		DailyRollingFileAppender dailyFileAppender;
		try
		{
			String clientFilename = "";
			if ( this.getFile() != null )
				clientFilename = this.getFile().replaceAll( "##customerName##", clientName );

			dailyFileAppender = new DailyRollingFileAppender();
			dailyFileAppender.setFile( clientFilename );
			dailyFileAppender.setAppend( getAppend() );
			dailyFileAppender.setBufferedIO( bufferedIO );
			dailyFileAppender.setBufferSize( bufferSize );
			dailyFileAppender.setEncoding( encoding );
			dailyFileAppender.setImmediateFlush( immediateFlush );
			dailyFileAppender.setLayout( layout );
			dailyFileAppender.setThreshold( threshold );
			dailyFileAppender.setName( name + "." + clientName );

		}
		catch ( Exception e )
		{
			LogLog.error( "Could not create an Appender. Reported error follows.", e );
			return null;
		}
		return dailyFileAppender;
	}

	@Override
	public synchronized void setFile( String fileName, boolean append, boolean bufferedIO, int bufferSize ) throws IOException
	{
		// override to "do nothing". there's no need to set a file in this class, it will be done when we create the decorated DailyRollingFileAppender
		// in the createFileAppender() method above
	}
	
	@Override
	public void close()
	{
		synchronized ( customerAppenders )
		{
			Collection<FileAppender> fileAppenders = customerAppenders.values();
			for ( Iterator<FileAppender> iter = fileAppenders.iterator() ; iter.hasNext() ; )
			{
				FileAppender fileAppender = iter.next();
				fileAppender.close();
			}
		}
	}

}
